package net.borlis.sample.horses;

import net.borlis.sample.horses.core.AppConfiguration;
import net.borlis.sample.horses.core.Horse;
import net.borlis.sample.horses.core.Odds;
import net.borlis.sample.horses.process.Bett;
import net.borlis.sample.horses.process.HorseRace;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static net.borlis.sample.horses.core.Denominator.byNumber;

/**
 * Created by Alexander on 21.12.2014.
 */
public class Main {

    private static Integer wonAmount = 0;
    private static Integer loseAmount = 0;

    public static void main(String[] args) {
        AppConfiguration config = loadConfiguration();
        Scanner scanner = new Scanner(System.in);
        String line;
        do {
            config.getOdds().print();
            line = scanner.nextLine().replaceAll("\n", "");
            // split line into arguments
            String[] arguments = line.split(" ");
            // process arguments
            if (arguments.length == 1) {
                if (arguments[0].equalsIgnoreCase("q"))
                    System.exit(0);
                if (arguments[0].equalsIgnoreCase("r")) {
                    config = loadConfiguration();
                }
                if (arguments[0].equalsIgnoreCase("h")) {
                    printHelp();
                }
            } else if (arguments.length > 1) {
                if (arguments[0].equalsIgnoreCase("W")) {
                    config.getOdds().setWinnerHorse(arguments[1]);
                } else if (arguments[0].matches("\\d")) {
                    try {
                        if (config.getInventory().bank() >= new Integer(arguments[1])) {
                            Bett bett = new Bett(new Integer(arguments[0]),
                                    config.getOdds(),
                                    new Integer(arguments[1]));
                            scheduleRace(config, bett);
                        } else {
                            System.out.println("Invalid bet " + arguments[1]);
                        }
                    } catch (IllegalArgumentException e) {
                        System.out.println("Invalid horse number " + arguments[0]);
                    }
                } else {
                    System.out.println("Invalid command: " + line);
                }
            }
        } while (!line.equalsIgnoreCase("q"));
    }

    private static void scheduleRace(AppConfiguration config, Bett bett) {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
        HorseRace race = new HorseRace(config);
        ScheduledFuture<List<Map.Entry<Horse, Integer>>> result
                = executor.schedule(race, 2, TimeUnit.SECONDS);
        System.out.print(" race ....");
        while (!result.isDone()) {
        }
        System.out.println();
        try {
            process(result.get(), config, bett);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    private static void printHelp() {
        System.out.println("---- help manual ----");
        System.out.println(" use Q or q to exit ");
        System.out.println(" use R or r to schedule bank refunds to default");
        System.out.println(" use W or w to make horse odds as maximum ");
        System.out.println(" use 'horse number' 'bet amount'  to make a bet, example '5 100' means $100 on 5th horse ");
    }

    private static void process(List<Map.Entry<Horse, Integer>> raseResult, AppConfiguration config, Bett bett) {
        Horse winner = raseResult.get(0).getKey();
        Odds odds = config.getOdds();
        if (winner.equals(bett.getHorse())) {
            Integer multiplier = odds.get(winner).equals(10) ? 1 : (10 - odds.get(winner));
            Integer winningSumm = multiplier * bett.getAmount();
            System.out.println("Payout "+ bett.getHorse().getName()+" amount " + winningSumm);
            config.getInventory().pay(winningSumm);
            wonAmount = wonAmount + winningSumm;
        } else {
            System.out.println("No payout "+ bett.getHorse().getName());
            config.getInventory().addToBank(bett.getAmount());
            loseAmount = loseAmount + bett.getAmount();
        }
        System.out.println("Your total success is " + (wonAmount - loseAmount) + " $");

        clearScreen(config.getInventory().bank());
    }

    private static AppConfiguration loadConfiguration() {
        AppConfiguration appConfiguration = new AppConfiguration();
        try {
            Configuration horses = new PropertiesConfiguration("horses.properties");
            Configuration odds = new PropertiesConfiguration("odds.properties");
            Iterator<String> horsePropertiesIterator = horses.getKeys();
            while (horsePropertiesIterator.hasNext()) {
                Integer horseNumber = Integer.valueOf(horsePropertiesIterator.next());
                Horse horse = new Horse(horseNumber, horses.getString("" + horseNumber));
                System.out.println(horseNumber + " " + horses.getString("" + horseNumber) + " odds:" + odds.getInt("" + horseNumber));
                appConfiguration.getOdds().put(horse, odds.getInt("" + horseNumber));
            }
            Configuration inventoryProps = new PropertiesConfiguration("inventory.properties");
            Iterator<String> inventoryPropertiesIterator = inventoryProps.getKeys();
            while (inventoryPropertiesIterator.hasNext()) {
                Integer value = new Integer(inventoryPropertiesIterator.next());
                Integer quantity = new Integer(inventoryProps.getInt("" + value));
                appConfiguration.getInventory().put(byNumber(value), quantity);
            }
            appConfiguration.getInventory().printBank();
            return appConfiguration;
        } catch (ConfigurationException cex) {
            System.out.println("Error in configuration setup");
            throw new IllegalStateException("Error in configuration setup");
        }
    }

    private static void clearScreen(Integer limit) {
        System.out.println();
        System.out.println("--------------------------------------------------------");
        System.out.println("---------------------ANOTHER ROUND-----------------------");
        System.out.println("--------------------------------------------------------");
        System.out.println("Funds limit: $"+limit);
        System.out.println();
    }
}
